local BinParser = {
    filename = "",
    size = 0
}

local log = require "log"
local cjson = require "cjson"
-- 增加缓存，减少频繁打开关闭文件, key为文件名, value为文件内容
local BinCache = {}

function BinParser:new(o, filename, size)
    o = o or {}
    setmetatable(o, self)
    self.__index = self
    self.filename = filename..".bin"
    self.bin_flag = filename..".flag"
    self.filekey = string.sub(filename, 19)
    self.size = size
    return o
end

function BinParser:create_file()
    local file = io.open(self.filename, "rb")
    if file then
        file:close()
        return
    end

    local cmd = 'dd if=/dev/zero of='..self.filename..' bs='..tostring(self.size)..' count=1'
    os.execute(cmd)
end

function BinParser:read_data(offset, length)
    -- bin_flag文件存在，则说明bin文件被外部修改，需要重读
    local bin_modify = io.open(self.bin_flag, "rb")
    -- 缓存里如果没有此文件，才打开文件读
    if BinCache[self.filekey] == nil or bin_modify then
        self:create_file()
        local file, err_info = io.open(self.filename, "rb")
        if file == nil then
            log:print(LOG_ERROR, "open file fail. filename: %s, %s", self.filename, err_info)
            return
        end
        log:print(LOG_ERROR, "open bin: %s, key: %s", self.filename, self.filekey)

        local flen = file:seek("end")
        file:seek("set")
        BinCache[self.filekey] = file:read(flen)
        file:close()
    end
    local result = {}
    local rd_end = offset + length
    if BinCache[self.filekey] ~= nil and rd_end <= #BinCache[self.filekey] then
        for i = offset + 1, rd_end do
            local ch = tonumber(string.byte(BinCache[self.filekey], i, i))
            table.insert(result, ch)
        end
    end
    log:print(LOG_DEBUG, "BinPaser len: %d, rd: %s", length, cjson.encode(result))
	
    if bin_modify then
        os.remove(self.bin_flag)
        log:print(LOG_ERROR, "delete bin_flag: %s", self.bin_flag)
    end
    return result
end

function BinParser:write_data(offset, data)
    self:create_file()
    local file, err_info = io.open(self.filename, "r+b")
    if file == nil then
        log:print(LOG_ERROR, "open file fail. filename: %s, %s", self.filename, err_info)
        return
    end
    local flen = file:seek("end")
    if offset + #data > flen then
        file:close()
        return
    end

    -- 缓存里如有，则不用再重复读
    local write_buffer = BinCache[self.filekey]
    if write_buffer == nil then
        file:seek("set")
        write_buffer = file:read(flen)
        log:print(LOG_ERROR, "read in write_data: %s", self.filename)
    end
    local i = offset + 1
    local j = 1
    while i <= offset + #data do
        write_buffer[i] = string.char(data[j])
        i = i + 1
        j = j + 1
    end

    file:seek("set")
    for i = 1, #write_buffer do
        file:write(write_buffer[i])
    end
    log:print(LOG_DEBUG, "write done")
    BinCache[self.filekey] = write_buffer
    file:close()
end

return BinParser
